package mornd.test2;

import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;

/**
 * @author: mornd
 * @dateTime: 2023/5/6 - 16:28
 * 模拟 Spring 如何在方法或类上获取 @Transactional 注解
 */
public class Demo3 {
    /**
     * spring 获取 @Transactional 的简单实现
     * spring 的注解可加在方法，类及父类，接口的方法，类上
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        StaticMethodMatcherPointcut matcher = new StaticMethodMatcherPointcut() {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                // 目标方法上寻找
                MergedAnnotations from1 = MergedAnnotations.from(method);
                if(from1.isPresent(Transactional.class)) {
                    return true;
                }
                // 目标类上寻找
                MergedAnnotations from2 = MergedAnnotations.from(targetClass);
                if(from2.isPresent(Transactional.class)) {
                    return true;
                }
                // 从继承树上去找 (类或接口被重写方法上是否标注)
                MergedAnnotations from3 = MergedAnnotations
                        .from(method, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
                if(from3.isPresent(Transactional.class)) {
                    return true;
                }

                // 从继承树上去找 (类或接口上是否标注)
                MergedAnnotations from4 = MergedAnnotations
                        .from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
                if(from4.isPresent(Transactional.class)) {
                    return true;
                }
                return false;
            }
        };
        boolean b1 = matcher.matches(Target1.class.getDeclaredMethod("foo"), Target1.class);
        boolean b2 = matcher.matches(Target1.class.getDeclaredMethod("bar"), Target1.class);
        System.out.println("b1 = " + b1);
        System.out.println("b2 = " + b2);

        boolean b3 = matcher.matches(Target2.class.getDeclaredMethod("foo"), Target2.class);
        System.out.println("b3 = " + b3);
    }

    //@Transactional
    static class Target1 {

        public void foo() {
            System.out.println("target1 foo");
        }

        @Transactional
        public void bar() {
            System.out.println("target1 bar");
        }
    }


    interface Inter2 {
        @Transactional
        void foo();
    }

    static class Target2 implements Inter2 {
        @Override
        public void foo() {
            System.out.println("target1 foo");
        }
    }
}
